package com.shuangseqiu.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.shuangseqiu.service.PredictionService;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 预测服务实现类，负责网页内容分析和结果处理
 */
@Service
public class PredictionServiceImpl implements PredictionService {

    private static final Logger logger = LoggerFactory.getLogger(PredictionServiceImpl.class);

    //匹配红球号码（至少6个）
    private static final Pattern RED_BALL_PATTERN = Pattern.compile("红球.{0,10}([0-9]{1,2}[,，、\\s]+){5,}\\d{1,2}");
    //匹配蓝球号码
    private static final Pattern BLUE_BALL_PATTERN = Pattern.compile("蓝球.{0,10}[0-9]{1,2}");
    //匹配胆码号码
    private static final Pattern DAN_MA_PATTERN = Pattern.compile("胆码.{0,10}[0-9]{1,2}[,，、\\s]*[0-9]{0,2}");
    //匹配拖码号码
    private static final Pattern TUO_MA_PATTERN = Pattern.compile("拖码.{0,10}([0-9]{1,2}[,，、\\s]+)+\\d{1,2}");
    //匹配推荐号码s
    private static final Pattern RECOMMEND_PATTERN = Pattern.compile("推荐号码.{0,20}([0-9]{1,2}[,，、\\s]+){6,}\\d{1,2}");
    
    @Autowired
    private HttpService httpService;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    @Value("${prediction.data.path}")
    private String dataPath;

    @Value("${async.core-pool-size:5}")
    private int corePoolSize;

    @Value("${async.max-pool-size:10}")
    private int maxPoolSize;

    @Value("${async.queue-capacity:100}")
    private int queueCapacity;
    
    // 线程池用于并发处理多个网页

    // 线程池用于并发处理多个网页
    private ExecutorService executorService;

    // 移除构造函数，使用 @PostConstruct 初始化
    @PostConstruct
    public void init() {
        // 初始化线程池
        this.executorService = new ThreadPoolExecutor(
                corePoolSize > 0 ? corePoolSize : 5,
                maxPoolSize > 0 ? maxPoolSize : 10,
                60L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(queueCapacity > 0 ? queueCapacity : 100),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
    }

    @Override
    public Map<String, Object> analyzeWebPageContent(String url) {
        logger.info("开始分析网页内容: {}", url);
        
        // 存储分析结果
        Map<String, Object> result = new HashMap<>();
        result.put("url", url);
        result.put("analysisTime", new Date());
        
        try {
            // 获取网页内容
            String pageContent = httpService.getPageContent(url);
            
            // 使用Jsoup解析HTML
            Document document = Jsoup.parse(pageContent);
            
            // 提取网页标题
            String title = document.title();
            result.put("title", title);
            
            // 提取正文内容
            String bodyText = document.body().text();
            
            // 分析与双色球相关的预测内容
            Map<String, Integer> predictionCount = countPredictionContent(bodyText);
            result.put("predictionCount", predictionCount);
            
            // 提取所有段落文本
            Elements paragraphs = document.select("p");
            List<String> paragraphTexts = paragraphs.stream()
                    .map(Element::text)
                    .filter(text -> text.length() > 20)
                    .collect(Collectors.toList());
            
            // 筛选包含双色球预测的段落
            List<String> predictionParagraphs = filterPredictionParagraphs(paragraphTexts);
            result.put("predictionParagraphs", predictionParagraphs);
            
            // 计算总体预测文章数量
            int totalPredictionArticles = calculateTotalPredictionArticles(predictionCount);
            result.put("totalPredictionArticles", totalPredictionArticles);
            
            logger.info("网页分析完成: {}, 预测文章数量: {}", url, totalPredictionArticles);
            
        } catch (Exception e) {
            logger.error("网页分析失败: {}", url, e);
            result.put("error", e.getMessage());
            result.put("success", false);
            return result;
        }
        
        result.put("success", true);
        return result;
    }

    @Override
    public void saveResultToJson(Map<String, Object> result, String fileName) {
        try {
            // 确保数据目录存在
            File directory = new File(dataPath);
            if (!directory.exists()) {
                Files.createDirectories(Paths.get(dataPath));
            }
            
            // 构建完整的文件路径
            String filePath = Paths.get(dataPath, fileName + ".json").toString();
            
            // 保存JSON文件
            objectMapper.writerWithDefaultPrettyPrinter().writeValue(new File(filePath), result);
            
            logger.info("结果已保存到文件: {}", filePath);
            
        } catch (IOException e) {
            logger.error("保存结果到JSON文件失败", e);
            throw new RuntimeException("保存结果到JSON文件失败", e);
        }
    }

    @Override
    public Map<String, Object> analyzeMultipleWebPages(String[] urls) {
        logger.info("开始分析多个网页，共 {} 个网址", urls.length);
        
        Map<String, Object> overallResult = new HashMap<>();
        overallResult.put("analysisTime", new Date());
        overallResult.put("totalUrls", urls.length);
        
        // 存储各个网页的分析结果
        List<Map<String, Object>> individualResults = new ArrayList<>();
        
        // 使用线程池并发处理
        List<CompletableFuture<Map<String, Object>>> futures = Arrays.stream(urls)
                .map(url -> CompletableFuture.supplyAsync(() -> analyzeWebPageContent(url), executorService))
                .collect(Collectors.toList());
        
        // 收集所有结果
        for (CompletableFuture<Map<String, Object>> future : futures) {
            try {
                Map<String, Object> result = future.get(5, TimeUnit.MINUTES); // 设置超时
                individualResults.add(result);
            } catch (Exception e) {
                logger.error("获取网页分析结果超时或失败", e);
                Map<String, Object> errorResult = new HashMap<>();
                errorResult.put("error", e.getMessage());
                errorResult.put("success", false);
                individualResults.add(errorResult);
            }
        }
        
        // 按照预测文章数量倒序排列
        individualResults.sort((a, b) -> {
            int countA = a.containsKey("totalPredictionArticles") ? ((Integer) a.get("totalPredictionArticles")) : 0;
            int countB = b.containsKey("totalPredictionArticles") ? ((Integer) b.get("totalPredictionArticles")) : 0;
            return Integer.compare(countB, countA); // 倒序排列
        });
        
        // 添加排序后的结果
        overallResult.put("results", individualResults);
        
        // 生成统计信息
        int successCount = (int) individualResults.stream().filter(r -> r.containsKey("success") && (Boolean) r.get("success")).count();
        overallResult.put("successCount", successCount);
        overallResult.put("failureCount", individualResults.size() - successCount);
        
        // 计算平均预测文章数量
        double avgPredictionCount = individualResults.stream()
                .filter(r -> r.containsKey("totalPredictionArticles"))
                .mapToInt(r -> (Integer) r.get("totalPredictionArticles"))
                .average()
                .orElse(0);
        overallResult.put("averagePredictionCount", Math.round(avgPredictionCount * 100) / 100.0);
        
        // 获取最多预测文章的网页
        if (!individualResults.isEmpty() && individualResults.get(0).containsKey("url")) {
            Map<String, Object> topResult = individualResults.get(0);
            overallResult.put("topPredictionUrl", topResult.get("url"));
            overallResult.put("topPredictionCount", topResult.get("totalPredictionArticles"));
        }
        
        // 生成当前日期的文件名并保存结果
        String currentDate = new SimpleDateFormat("yyyyMMdd").format(new Date());
        saveResultToJson(overallResult, currentDate);
        
        logger.info("多网页分析完成，成功分析 {} 个网页", successCount);
        
        return overallResult;
    }

    /**
     * 统计文本中包含的双色球预测内容类型和数量
     */
    private Map<String, Integer> countPredictionContent(String text) {
        Map<String, Integer> countMap = new HashMap<>();
        
        countMap.put("redBall", countPatternMatches(RED_BALL_PATTERN, text));
        countMap.put("blueBall", countPatternMatches(BLUE_BALL_PATTERN, text));
        countMap.put("danMa", countPatternMatches(DAN_MA_PATTERN, text));
        countMap.put("tuoMa", countPatternMatches(TUO_MA_PATTERN, text));
        countMap.put("recommend", countPatternMatches(RECOMMEND_PATTERN, text));
        
        return countMap;
    }

    /**
     * 计算正则表达式匹配的次数
     */
    private int countPatternMatches(Pattern pattern, String text) {
        Matcher matcher = pattern.matcher(text);
        int count = 0;
        while (matcher.find()) {
            count++;
        }
        return count;
    }

    /**
     * 筛选包含双色球预测的段落
     */
    private List<String> filterPredictionParagraphs(List<String> paragraphs) {
        List<String> predictionParagraphs = new ArrayList<>();
        
        for (String paragraph : paragraphs) {
            if (containsPredictionKeywords(paragraph)) {
                predictionParagraphs.add(paragraph);
            }
        }
        
        return predictionParagraphs;
    }

    /**
     * 检查文本是否包含预测相关关键词
     */
    private boolean containsPredictionKeywords(String text) {
        String lowerText = text.toLowerCase();
        return lowerText.contains("双色球") && 
               (lowerText.contains("预测") || 
                lowerText.contains("分析") || 
                lowerText.contains("推荐") || 
                lowerText.contains("胆码") || 
                lowerText.contains("拖码") || 
                lowerText.contains("红球") || 
                lowerText.contains("蓝球"));
    }

    /**
     * 计算总的预测文章数量
     */
    private int calculateTotalPredictionArticles(Map<String, Integer> predictionCount) {
        // 这里采用加权计算方式，不同类型的预测权重不同
        int redBallWeight = 3;
        int blueBallWeight = 2;
        int danMaWeight = 2;
        int tuoMaWeight = 2;
        int recommendWeight = 4;
        
        return predictionCount.getOrDefault("redBall", 0) * redBallWeight +
               predictionCount.getOrDefault("blueBall", 0) * blueBallWeight +
               predictionCount.getOrDefault("danMa", 0) * danMaWeight +
               predictionCount.getOrDefault("tuoMa", 0) * tuoMaWeight +
               predictionCount.getOrDefault("recommend", 0) * recommendWeight;
    }

    /**
     * 应用关闭时关闭线程池
     */
    @Override
    protected void finalize() throws Throwable {
        try {
            if (executorService != null && !executorService.isShutdown()) {
                executorService.shutdown();
                executorService.awaitTermination(30, TimeUnit.SECONDS);
            }
        } finally {
            super.finalize();
        }
    }
}